/////////////////////////////////////////////////////////////////////////////
// Original code from libhdfs3. Copyright (c) 2013 - 2014, Pivotal Inc.
// All rights reserved. Author: Zhanwei Wang
/////////////////////////////////////////////////////////////////////////////
//  Modifications by Kumo Inc.
// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//



#pragma once


#include <kmhdfs/server/located_block.h>
#include <memory>
#include <kmhdfs/client/ec_policy.h>

#include <cassert>

namespace Hdfs {
    namespace Internal {
        class LocatedBlocks {
        public:
            virtual ~LocatedBlocks() = default;

            virtual int64_t getFileLength() const = 0;

            virtual void setFileLength(int64_t fileLength) = 0;

            virtual bool isLastBlockComplete() const = 0;

            virtual void setIsLastBlockComplete(bool lastBlockComplete) = 0;

            virtual std::shared_ptr<LocatedBlock> getLastBlock() = 0;

            virtual void setLastBlock(std::shared_ptr<LocatedBlock> lastBlock) = 0;

            virtual bool isUnderConstruction() const = 0;

            virtual void setUnderConstruction(bool underConstruction) = 0;

            virtual const LocatedBlock *findBlock(int64_t position) = 0;

            virtual const LocatedBlock *findBlock(int64_t position, int32_t &targetBlockIdx) = 0;

            virtual std::vector<LocatedBlock> &getBlocks() = 0;

            virtual std::shared_ptr<ECPolicy> getEcPolicy() const = 0;

            virtual void setEcPolicy(std::shared_ptr<ECPolicy> ecPolicy) = 0;

            virtual void insertRange(int32_t blockIdx, std::vector<LocatedBlock> &newBlocks) = 0;
        };

        /**
         * Collection of blocks with their locations and the file length.
         */
        class LocatedBlocksImpl : public LocatedBlocks {
        public:
            int64_t getFileLength() const {
                return fileLength;
            }

            void setFileLength(int64_t fileLength) {
                this->fileLength = fileLength;
            }

            bool isLastBlockComplete() const {
                return lastBlockComplete;
            }

            void setIsLastBlockComplete(bool lastBlockComplete) {
                this->lastBlockComplete = lastBlockComplete;
            }

            std::shared_ptr<LocatedBlock> getLastBlock() {
                assert(!lastBlockComplete);
                return lastBlock;
            }

            void setLastBlock(std::shared_ptr<LocatedBlock> lastBlock) {
                this->lastBlock = lastBlock;
            }

            bool isUnderConstruction() const {
                return underConstruction;
            }

            void setUnderConstruction(bool underConstruction) {
                this->underConstruction = underConstruction;
            }

            const LocatedBlock *findBlock(int64_t position);

            const LocatedBlock *findBlock(int64_t position, int32_t &targetBlockIdx);

            std::vector<LocatedBlock> &getBlocks() {
                return blocks;
            }

            std::shared_ptr<ECPolicy> getEcPolicy() const {
                return ecPolicy;
            }

            void setEcPolicy(std::shared_ptr<ECPolicy> policy) {
                ecPolicy = policy;
            }

            void insertRange(int32_t blockIdx, std::vector<LocatedBlock> &newBlocks);

            void addAll(std::vector<LocatedBlock> &oldBlocks, int32_t index, std::vector<LocatedBlock> &newBlocks,
                        int32_t start, int32_t end);

        private:
            bool lastBlockComplete;
            bool underConstruction;
            int64_t fileLength;
            std::shared_ptr<LocatedBlock> lastBlock;
            std::vector<LocatedBlock> blocks;
            bool isStriped = false;
            std::shared_ptr<ECPolicy> ecPolicy = nullptr;
        };
    }
}
